package com.example.threadSimple;

import java.util.Optional;

/**
 * @Author: Ah Nan
 * @Description: Optional demo
 * @Date: 8:46 2020/7/2
 * @throw: 请描述异常信息
 */
public class OptionalSimple {


    public static void main(String[] args) {

//        whenCreateEmptyOptional_thenNull();

//        whenCreateOfEmptyOptional_thenNullPointerException();

//        whenCreateOfNullableOptional_thenOk();

//        whenEmptyValue_thenReturnDefault();

//        whenValueNotNull_thenIgnoreDefault();

//        givenEmptyValue_whenCompare_thenOk();

//        givenPresentValue_whenCompare_thenOk();

//        whenThrowException_thenOk();

//        whenMap_thenOk();

//        whenFlatMap_thenOk();

//        whenFilter_thenOk();

        whenChaining_thenOk();
    }


    /**
     * eg: NoSuchElementException
     */
    public static void whenCreateEmptyOptional_thenNull() {
        //毫不奇怪，尝试访问 emptyOpt 变量的值会导致 NoSuchElementException。
        Optional<PaymentModel> emptyOpt = Optional.empty();
        emptyOpt.get();
    }

    /**
     * eg: NullPointerException
     */
    public static void whenCreateOfEmptyOptional_thenNullPointerException() {
        //你可以使用  of() 和 ofNullable() 方法创建包含值的 Optional。两个方法的不同之处在于如果你把 null 值作为参数传递进去，of() 方法会抛出 NullPointerException：
        PaymentModel paymentModel = new PaymentModel();
        Optional<PaymentModel> opt = Optional.of(paymentModel);
        opt = Optional.ofNullable(paymentModel);
    }

    /**
     * eg: 访问 Optional 对象的值
     */
    public static void whenCreateOfNullableOptional_thenOk() {
        String name = "John";
        Optional<String> opt = Optional.ofNullable(name);
        System.out.println("John" + opt.get());

        //检查是否有值的另一个选择是 ifPresent() 方法。该方法除了执行检查，还接受一个Consumer(消费者) 参数，如果对象不是空的，就对执行传入的 Lambda 表达式：
        PaymentModel paymentModel = new PaymentModel();
        paymentModel.setPaymentAmount(1000);
        paymentModel.setCallUrl("100");
        opt.ifPresent(pm -> System.out.println(paymentModel.getCallUrl() + paymentModel.getCallUrl()));
    }

    /**
     * eg: orElse API返回默认值，默认值为null情况
     */
    public static void whenEmptyValue_thenReturnDefault() {
        //Optional 类提供了 API 用以返回对象值，或者在对象为空的时候返回默认值。这里你可以使用的第一个方法是 orElse()，它的工作方式非常直接，如果有值则返回该值，否则返回传递给它的参数值：
        PaymentModel paymentModel = null;
        PaymentModel paymentModel2 = new PaymentModel();
        paymentModel2.setPaymentAmount(1000);
        paymentModel2.setCallUrl("100");
        PaymentModel result = Optional.ofNullable(paymentModel).orElse(paymentModel2);
        //这里 user 对象是空的，所以返回了作为默认值的 user2。
        System.out.println(paymentModel2.getCallUrl() + "   " + result.getCallUrl());
    }

    /**
     * eg: orElse API返回默认值2，默认值有值情况
     */
    public static void whenValueNotNull_thenIgnoreDefault() {

        //如果对象的初始值不是 null，那么默认值会被忽略：
        PaymentModel paymentModel = new PaymentModel(100, "callUrl");
        PaymentModel paymentModel2 = new PaymentModel(2000, "callUrl2");
        PaymentModel result = Optional.ofNullable(paymentModel).orElse(paymentModel2);
        //paymentModel有值，paymentModel2没有值则返回paymentModel
        System.out.println(result.getCallUrl());
    }

    /**
     * eg: orElse API 与 orElseGet() API异同 默认参数为空情况
     */
    public static void givenEmptyValue_whenCompare_thenOk() {

        //下面的代码中，两种方法都调用了 createNewPaymentModel() 方法，这个方法会记录一个消息并返回 paymentModel 对象。
        PaymentModel paymentModel = null;
        System.out.println("Using orElse");
        PaymentModel result = Optional.ofNullable(paymentModel).orElse(createNewPaymentModel());
        System.out.println("Using orElseGet");
        PaymentModel result2 = Optional.ofNullable(paymentModel).orElseGet(() -> createNewPaymentModel());
        //由此可见，当对象为空而返回默认对象时，行为并无差异。
    }

    private static PaymentModel createNewPaymentModel() {
        System.out.println("Creating New paymentModel");
        return new PaymentModel(100, "callUrl");
    }

    /**
     * eg: orElse API 与 orElseGet() API异同 默认参数不为空情况
     */
    public static void givenPresentValue_whenCompare_thenOk() {
        //两个 Optional  对象都包含非空值，两个方法都会返回对应的非空值。不过，orElse() 方法仍然创建了 User 对象。与之相反，orElseGet() 方法不创建 User 对象。在执行较密集的调用时，比如调用 Web 服务或数据查询，这个差异会对性能产生重大影响。
        PaymentModel paymentModel = new PaymentModel(100, "callUrl");
        System.out.println("Using orElse");
        PaymentModel result = Optional.ofNullable(paymentModel).orElse(createNewPaymentModel());
        System.out.println("Using orElseGet");
        PaymentModel result2 = Optional.ofNullable(paymentModel).orElseGet(() -> createNewPaymentModel());
    }

    /**
     * eg: orElseThrow API
     */
    public static void whenThrowException_thenOk() {
        //除了 orElse() 和 orElseGet() 方法，Optional 还定义了 orElseThrow() API —— 它会在对象为空的时候抛出异常，而不是返回备选的值：
        //这个方法让我们有更丰富的语义，可以决定抛出什么样的异常，而不总是抛出 NullPointerException。
        PaymentModel paymentModel = null;
        PaymentModel result = Optional.ofNullable(paymentModel)
                .orElseThrow(() -> new IllegalArgumentException());
    }

    /**
     * eg:  map() 转换值 API
     */
    public static void whenMap_thenOk() {

        //paymentModel.getCallUrl()为空则返回orElse里面的值
        PaymentModel paymentModel = new PaymentModel();
        String callUrl = Optional.ofNullable(paymentModel)
                .map(u -> paymentModel.getCallUrl()).orElse("default@gmail.com");
        System.out.println(callUrl + "  " + paymentModel.getCallUrl());

        //paymentModel.getCallUrl()不为空则返回getCallUrl()
        PaymentModel paymentModel2 = new PaymentModel(100, "callurll");
        String callUrl2 = Optional.ofNullable(paymentModel)
                .map(u -> paymentModel2.getCallUrl()).orElse("default@gmail.com");
        System.out.println(callUrl2 + "  " + paymentModel2.getCallUrl());

    }

    /**
     * eg:  flatMap() 转换值 API
     */
    public static void whenFlatMap_thenOk() {
        //对于Optional的map和flatmap：map是把结果自动封装成一个Optional，但是flatmap需要你自己去封装。
        PaymentModel paymentModel = new PaymentModel(100, "anna@gmail.com");
        paymentModel.setPosition("Developer");
        String position = Optional.ofNullable(paymentModel)
                .flatMap(u -> u.getPosition()).orElse("default");
        System.out.println(position + " " + paymentModel.getPosition().get());
    }

    /**
     * eg:  filter() 过滤值
     */
    public static void whenFilter_thenOk() {
        //filter() 接受一个 Predicate 参数，返回测试结果为 true 的值。如果测试结果为 false，会返回一个空的 Optional。
        PaymentModel paymentModel = new PaymentModel(123456, "anna@gmail.com");
        Optional<PaymentModel> result = Optional.ofNullable(paymentModel)
                .filter(u -> u.getCallUrl() != null && u.getCallUrl().contains("@"));
        System.out.println(result.isPresent() + " " + result.getClass());
    }

    /**
     * eg:  Optional 类的链式方法
     */
    public static void whenChaining_thenOk() {
        UserModel user = new UserModel("anna@gmail.com", "1234");
        String result = Optional.ofNullable(user)
                .flatMap(UserModel::getAddress)
                .flatMap(Address::getCountry)
                .map(PaymentModel::getCallUrl)
                .orElse("default");
        System.out.println(result + " default");
    }

}
